using System.Collections.Specialized;
using System.Text.RegularExpressions;

namespace FaultTolerantWebService.Common
{
    /// <summary>
    /// Classe qui simplifie la gestion des parametre de ligne de commande
    /// <example>
    /// <code>
    /// public static void Main(string[] args) {
    ///     Arguments arguments = new Arguments(args);
    /// 
    ///     // The user has to write sample.exe -message yeay
    ///     // or sample.exe --message:"yeay"
    ///     // or many other syntaxes :)
    ///     if (arguments.Contains("message")) {
    ///        Console.WriteLn("Hello :{0}", arguments["message"]);
    ///     }
    /// }
    /// </code>
    /// </example>
    /// </summary>
    public class Arguments
    {
        #region Protected Object Members

        private StringDictionary Parameters;

        #endregion

        #region Public Constructors

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="Args"></param>
        public Arguments(string[] Args)
        {
            Parameters = new StringDictionary();
            Regex Spliter = new Regex(@"^-{1,2}|^/|=|:",
                RegexOptions.IgnoreCase | RegexOptions.Compiled);

            Regex Remover = new Regex(@"^['""]?(.*?)['""]?$",
                RegexOptions.IgnoreCase | RegexOptions.Compiled);

            string Parameter = null;
            string[] Parts;

            // Valid parameters forms:
            // {-,/,--}param{ ,=,:}((",')value(",'))
            // Examples: 
            // -param1 value1 --param2 /param3:"Test-:-work" 
            //   /param4=happy -param5 '--=nice=--'
            foreach (string Txt in Args)
            {
                // Look for new parameters (-,/ or --) and a
                // possible enclosed value (=,:)
                Parts = Spliter.Split(Txt, 3);

                switch (Parts.Length)
                {
                    // Found a value (for the last parameter 
                    // found (space separator))
                    case 1:
                        if (Parameter != null)
                        {
                            if (!Parameters.ContainsKey(Parameter))
                            {
                                Parts[0] =
                                    Remover.Replace(Parts[0], "$1");

                                Parameters.Add(Parameter, Parts[0]);
                            }
                            Parameter = null;
                        }
                        // else Error: no parameter waiting for a value (skipped)
                        break;

                    // Found just a parameter
                    case 2:
                        // The last parameter is still waiting. 
                        // With no value, set it string.Empty.
                        if (Parameter != null)
                        {
                            if (!Parameters.ContainsKey(Parameter))
                                Parameters.Add(Parameter, string.Empty);
                        }
                        Parameter = Parts[1];
                        break;

                    // Parameter with enclosed value
                    case 3:
                        // The last parameter is still waiting. 
                        // With no value, set it to true.
                        if (Parameter != null)
                        {
                            if (!Parameters.ContainsKey(Parameter))
                                Parameters.Add(Parameter, string.Empty);
                        }

                        Parameter = Parts[1];

                        // Remove possible enclosing characters (",')
                        if (!Parameters.ContainsKey(Parameter))
                        {
                            Parts[2] = Remover.Replace(Parts[2], "$1");
                            Parameters.Add(Parameter, Parts[2]);
                        }

                        Parameter = null;
                        break;
                }
            }
            // In case a parameter is still waiting
            if (Parameter != null)
            {
                if (!Parameters.ContainsKey(Parameter))
                    Parameters.Add(Parameter, string.Empty);
            }
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Get the parameter list size.
        /// </summary>
        /// <returns>The parameter list size.</returns>
        public int Count
        {
            get
            {
                return Parameters.Count;
            }
        }

        #endregion

        #region Public Indexer

        /// <summary>
        /// Retrieve a parameter value if it exists 
        /// (overriding C# indexer property)
        /// </summary>
        /// <param name="Param"></param>
        /// <returns></returns>
        public string this[string Param]
        {
            get
            {
                return (Parameters[Param]);
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Test if the arguments contains the given parameters
        /// </summary>
        /// <param name="Param"></param>
        /// <returns></returns>
        public bool Contains(string Param)
        {
            return Parameters[Param] != null;
        }        

        #endregion
    }
}
